#include "arch/mips/MIPSVBasicBlockBuilder.h"

#include "crossbit/VBlock.h"
#include "string.h"

using namespace crossbit;

MIPSVBasicBlockBuilder::MIPSVBasicBlockBuilder()
{
		memset( usedRegTable, 0, MAXREGS );
		memset( luIndex, 0, MAXREGS );
}

void MIPSVBasicBlockBuilder::getReady(XTMemAddr pc)
{
		VBasicBlockBuilder::getReady(pc);
		memset( usedRegTable, 0, MAXREGS );
		memset( luIndex, 0, MAXREGS );
}

void MIPSVBasicBlockBuilder::add(VInst *inst)
{
		Opcode opcode = inst->getOpcode();
		Opkind opkind = inst->getOpkind();

		// We have to bail out if a SYSCALL instruction is met
		// to do the system call emulation since SimpleScalar
		// is based on different syscall set than linux.

		if( (opcode == OP_GET) && (inst->getOperand(1).reg == inst->getOperand(2).reg))
		{
				XTInt32 temp = inst->getOperand(1).reg;
				if( usedRegTable[temp] == 0 )
				{
						usedRegTable[temp] |= REGUSED;
				}
				else
				{
						return;
				}
		}
		else if( (opcode == OP_PUT) && (inst->getOperand(1).reg == inst->getOperand(2).reg) )
		{

				//record the latest PUT inst of reg
				XTInt32 i = inst->getOperand(2).reg;
				usedRegTable[i] |= REGDEF;
				if( luIndex[i] != 0 )
						bb_vblock->setVbIlist(luIndex[i], NULL);
				luIndex[i] = bb_vblock->size(); 

				//return;
		}
		else if ( opcode == OP_SYSCALL			||
						opkind == OPK_CONTROLTRANSFER	||
						opcode == OP_HALT)
		{
				bb_end = true;
		}

		bb_vblock->push_back(inst);
}

VBlock* MIPSVBasicBlockBuilder::wrapUp(XTMemAddr pc)
{
		VBlock::vb_iterator it = bb_vblock->begin();
		while( it != bb_vblock->end() )
		{
				if( *it == NULL )
				{
						it = bb_vblock->erase(it);
				}
				else
						++it;
		}

		//Added by suntingtao , remove the unnecessary 'MOV' intermediate instrution
		it = bb_vblock -> begin();
		VBlock::vb_iterator tmp;
		while( it != bb_vblock -> end() ){
				if( (*it) -> getOpcode() == OP_MOV ){
						// MOV src , dst
						XTRegNum src = (*it) -> getOperand(1).reg;
						XTRegNum dst = (*it) -> getOperand(2).reg;
						tmp = it;
						tmp++;
						bool removable = true;
						while( tmp != bb_vblock -> end() ){
								int n = (*tmp) -> getOperandNum();
								Operand opr;
								if( n ){
										opr = (*tmp) -> getOperand(n);
								}
								if( opr.type == Operand::VREG_DEF && (opr.reg == src || opr.reg == dst))
										removable = false;	
								tmp++;
						}
						if( removable ){
								tmp = it;
								tmp++;
								while( tmp != bb_vblock -> end() ){
										XTInt32 n = (*tmp) -> getOperandNum();
										for( XTInt32 i = 1 ; i <= n ; i++ ){
												Operand opr = (*tmp) -> getOperand(i);
												if( opr.type == Operand::VREG_USE && opr.reg == dst ){
														opr.reg = src; 	
														(*tmp) -> setOperand( i , opr);
												}
										}
										tmp++;
								}
								it = bb_vblock -> erase(it);
						}else
								++it;
				}else
						++it;
		}			
		// -->	
		return VBasicBlockBuilder::wrapUp(pc);
}
